package zhoug.zui;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import zhoug.logging.Logger;
import zhoug.zui.ints.OnProgressListener;

import java.text.MessageFormat;

import androidx.annotation.DrawableRes;
import androidx.annotation.Nullable;

/**
 * 自定义星星组件
 * zui_style_ZUIRatingBar
 *
 * @Author 35574
 * @Date 2020/7/29
 * @Description
 */
public class ZUIRatingBar extends View {
    private static final String TAG = ">>>ZUIRatingBar";
    private static final boolean DEBUG = false;
    /**
     * 每个星星之间的间距
     */
    private int starSpace;
    /**
     * 星星总数
     */
    private int maxStar;
    /**
     * 当前星星数
     */
    private float rating;
    /**
     * 总进度:所有星星表示的总进度
     */
    private int maxProgress;
    /**
     * 1个星星的最小改变步数:0-1;
     * eg:0.5:表示可以改变0.5个星星状态
     */
    private float stepSize;

    private Paint paint;
    private Rect src = new Rect();
    private Rect des = new Rect();
    private int desWidth = 0;
    private int desHeight = 0;
    private int top = 0;

    private boolean changeEnable = false;
    private int left;
    private int right;

    private Bitmap frontBitmap;
    private Bitmap backBitmap;

    private OnProgressListener mOnProgressListener;

    public ZUIRatingBar(Context context) {
        this(context, null);
    }

    public ZUIRatingBar(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, R.attr.ZUIRatingBar_theme);
    }

    public ZUIRatingBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        decodeStyleAttr(context, attrs, defStyleAttr, R.style.ZUIRatingBar_def);
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setAntiAlias(true);
    }

    private void decodeStyleAttr(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ZUIRatingBar, defStyleAttr, defStyleRes);
        //星星
        Drawable frontDrawable = typedArray.getDrawable(R.styleable.ZUIRatingBar_zui_frontDrawable);
        frontBitmap = getBitmap(frontDrawable);
        Drawable backDrawable = typedArray.getDrawable(R.styleable.ZUIRatingBar_zui_backDrawable);
        backBitmap = getBitmap(backDrawable);
        starSpace = (int) typedArray.getDimension(R.styleable.ZUIRatingBar_zui_starSpace, 10);
        changeEnable = typedArray.getBoolean(R.styleable.ZUIRatingBar_zui_changeEnable, false);
        float stepSize = typedArray.getFloat(R.styleable.ZUIRatingBar_zui_stepSize, 1f);

        maxStar = typedArray.getInteger(R.styleable.ZUIRatingBar_zui_maxStar, 5);
        rating = typedArray.getFloat(R.styleable.ZUIRatingBar_zui_rating, 0);
        maxProgress = typedArray.getInteger(R.styleable.ZUIRatingBar_zui_maxProgress, 100);
        typedArray.recycle();
        setStepSize(stepSize);
    }


    private float r2 = 0;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (!changeEnable) {
            return super.onTouchEvent(event);
        }
        int action = event.getAction();
        if (action == MotionEvent.ACTION_DOWN) {
            if (getParent() != null) {
                getParent().requestDisallowInterceptTouchEvent(true);
            }
        }

//        Logger.d(TAG, "onTouchEvent: ");
        float x = event.getX();
//        Logger.d(TAG, "onTouchEvent: x="+x);

        if (x <= left) {
            r2 = 0;
        } else if (x >= right) {
            r2 = maxStar;
        } else if (x <= left + desWidth) {
            r2 = (x - left) / desWidth;
        } else if (x < left + desWidth + starSpace) {
            r2 = 1;
        } else if (x > left + desWidth + starSpace) {
            //前end个完全显示
            int end = (int) ((x - left) / (desWidth + starSpace));
//            Logger.d(TAG, "onTouchEvent: end="+end);
            float s = x - left - end * (desWidth + starSpace);
            float add = s / desWidth;
            add = add > 1 ? 1 : add;
            r2 = end + add;

        }
//        Logger.d(TAG, "onTouchEvent: r2="+r2);
        r2 = computeRating(r2);
        if (rating != r2) {
            rating = r2;
            invalidate();
//            Logger.d(TAG, "onTouchEvent: 刷新rating="+rating);
        }

        if (action == MotionEvent.ACTION_UP) {
            if (mOnProgressListener != null) {
                mOnProgressListener.onProgressChange(getProgress());
            }
        }

        return true;
    }

    /**
     * 计算出需要画的星星数(被步数限制后的)
     *
     * @param rating 星星数
     * @return
     */
    private float computeRating(float rating) {
        rating += 0.00001;//精度损失
        if (rating < 0) {
            rating = 0;
        } else if (rating > maxStar) {
            rating = maxStar;
        }
        //rating=1.7
        int a = (int) rating; //a=1
        float b = rating - a;//b=0.7
        if (b == 0) {
            return rating;
        } else {
            //stepSize=0.5
            float c = (b / stepSize);//1.4
            int x = (int) c;//x=1
            if (x == c) {
                return a + c * stepSize;
            } else {
                int z = (c - x) >= 0.5 ? 1 : 0;//以stepSize四舍五入
                return a + (x + z) * stepSize;
            }
        }


    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (frontBitmap == null) {
            setFrontBitmap(R.drawable.zui_ratingbar_front);
        }
        if (backBitmap == null) {
            setBackBitmap(R.drawable.zui_ratingbar_back);
        }
        if (DEBUG) {
            Logger.d(TAG, "onMeasure:rating=" + rating);
        }
        rating = computeRating(rating);
        if (DEBUG) {
            Logger.d(TAG, "onMeasure:rating=" + rating);
        }
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);//宽度
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);//高度
        int imgWidth;
        int imgHeight;
        int measureWidth;
        int measureHeight;

        if (DEBUG) {
            Logger.d(TAG, "onMeasure:widthSize=" + widthSize);
            Logger.d(TAG, "onMeasure:heightSize=" + heightSize);
            Logger.d(TAG, "onMeasure:backBitmap.w=" + backBitmap.getWidth());
            Logger.d(TAG, "onMeasure:backBitmap.h=" + backBitmap.getHeight());
        }
        if (widthMode != MeasureSpec.EXACTLY && heightMode != MeasureSpec.EXACTLY) {
            if (DEBUG) {
                Logger.d(TAG, "onMeasure:宽高匹配内容");
            }
            //宽高匹配内容,更具图片宽高计算出宽高
            int w = getWidthByImageWidth(backBitmap.getWidth());
            int h = getHeightByImageHeight(backBitmap.getHeight());
            measureWidth = getBestSize(w, widthSize);
            measureHeight = getBestSize(h, heightSize);
            //根据宽高计算显示图片大小
            imgWidth = getImageWidthByWidth(measureWidth);
            imgHeight = getImageHeightByHeight(measureHeight);
            //计算图片缩放
            float scaleX = ((float) imgWidth / (float) backBitmap.getWidth());
            float scaleY = ((float) imgHeight / (float) backBitmap.getHeight());
            float scale = Math.min(scaleX, scaleY);
            if (DEBUG) {
                Logger.d(TAG, "onMeasure:scale=" + scale);
            }
            //最终图片大小
            desWidth = (int) (backBitmap.getWidth() * scale);
            desHeight = (int) (backBitmap.getHeight() * scale);
        } else if (widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY) {
            if (DEBUG) {
                Logger.d(TAG, "onMeasure:宽高确定");
            }
            measureWidth = widthSize;
            measureHeight = heightSize;
            //根据宽高计算显示图片大小
            imgWidth = getImageWidthByWidth(measureWidth);
            imgHeight = getImageHeightByHeight(measureHeight);
            //计算图片缩放
            float scaleX = ((float) imgWidth / (float) backBitmap.getWidth());
            float scaleY = ((float) imgHeight / (float) backBitmap.getHeight());
            float scale = Math.min(scaleX, scaleY);
            if (DEBUG) {
                Logger.d(TAG, "onMeasure:scale=" + scale);
            }
            //最终图片大小
            desWidth = (int) (backBitmap.getWidth() * scale);
            desHeight = (int) (backBitmap.getHeight() * scale);

        } else if (widthMode == MeasureSpec.EXACTLY) {
            if (DEBUG) {
                Logger.d(TAG, "onMeasure:宽度确定,高度自适应");
            }
            measureWidth = widthSize;
            imgWidth = getImageWidthByWidth(measureWidth);
            if (DEBUG) {
                Logger.d(TAG, "onMeasure:imgWidth="+imgWidth);
            }
            //计算图片缩放
            float scaleX = ((float) imgWidth / (float) backBitmap.getWidth());
            if (DEBUG) {
                Logger.d(TAG, "onMeasure:scaleX="+scaleX);
            }
            //根据缩放计算需要的高度
            int h = getHeightByImageHeight((int) (scaleX * backBitmap.getHeight()));
            if (DEBUG) {
                Logger.d(TAG, "onMeasure:h="+h);
            }
            measureHeight = getBestSize(h, heightSize);
            if (DEBUG) {
                Logger.d(TAG, "onMeasure:measureHeight="+measureHeight);
            }
            imgHeight = getImageHeightByHeight(measureHeight);
            if (DEBUG) {
                Logger.d(TAG, "onMeasure:imgHeight="+imgHeight);
            }
            float scaleY = ((float) imgHeight / (float) backBitmap.getHeight());
            if (DEBUG) {
                Logger.d(TAG, "onMeasure:scaleY="+scaleY);
            }
            float scale = Math.min(scaleX, scaleY);
            if (DEBUG) {
                Logger.d(TAG, "onMeasure:scale=" + scale);
            }
            //最终图片大小
            desWidth = (int) (backBitmap.getWidth() * scale);
            desHeight = (int) (backBitmap.getHeight() * scale);
        } else {
            if (DEBUG) {
                Logger.d(TAG, "onMeasure:高度确定,宽度自适应");
            }
            measureHeight = heightSize;
            imgHeight = getImageHeightByHeight(measureHeight);
            float scaleY = ((float) imgHeight / (float) backBitmap.getHeight());
            if (DEBUG) {
                Logger.d(TAG, "onMeasure:scaleY="+scaleY);
            }
            int w = getWidthByImageWidth((int) (scaleY * backBitmap.getWidth()));
            measureWidth= getBestSize(w, widthSize);
            imgWidth = getImageWidthByWidth(measureWidth);
            float scaleX = ((float) imgWidth / (float) backBitmap.getWidth());
            float scale = Math.min(scaleX, scaleY);
            if (DEBUG) {
                Logger.d(TAG, "onMeasure:scale=" + scale);
            }
            //最终图片大小
            desWidth = (int) (backBitmap.getWidth() * scale);
            desHeight = (int) (backBitmap.getHeight() * scale);
        }
        if (DEBUG) {
            Logger.d(TAG, "onMeasure:" + MessageFormat.format("图片大小[{0},{1}]", desWidth, desHeight));
            Logger.d(TAG, "onMeasure:" + MessageFormat.format("组件大小[{0},{1}]", measureWidth, measureHeight));
        }
        top = (measureHeight - desHeight) / 2;
        setMeasuredDimension(measureWidth, measureHeight);
    }

    private int getBestSize(int size, int maxSize) {
        if (maxSize > 0 && size > 0) {
            return Math.min(size, maxSize);
        }
        if (maxSize > 0) {
            return maxSize;
        }

        return size;
    }

    /**
     * 根据图片宽度计算理想的组件宽度
     *
     * @param imgWidth 图片宽度
     * @return
     */
    private int getWidthByImageWidth(int imgWidth) {
        return imgWidth * maxStar + (maxStar - 1) * starSpace + getPaddingEnd() + getPaddingStart();
    }

    /**
     * 根据图片高度计算理想的组件高度
     *
     * @param imgHeight 图片高度
     * @return
     */
    private int getHeightByImageHeight(int imgHeight) {
        return imgHeight + getPaddingTop() + getPaddingBottom();
    }

    /**
     * 根据宽度计算出图片的宽度
     *
     * @param width 组件宽
     * @return
     */
    private int getImageWidthByWidth(int width) {
        return (width - getPaddingStart() - getPaddingEnd() - (maxStar - 1) * starSpace) / maxStar;
    }

    /**
     * 根据高度计算出图片的高度
     *
     * @param height 组件高度
     * @return
     */
    private int getImageHeightByHeight(int height) {
        return height - getPaddingBottom() - getPaddingBottom();
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //画空星
        if (backBitmap != null) {
            for (int i = 0; i < maxStar; i++) {
                src.left = 0;
                src.top = 0;
                src.right = backBitmap.getWidth();
                src.bottom = backBitmap.getHeight();

                des.left = getPaddingStart() + (desWidth + starSpace) * i;
                if (i == 0 && left == 0) {
                    left = getPaddingStart();
                }
                des.top = top;
                des.right = des.left + desWidth;
                des.bottom = des.top + desHeight;
                if (i == maxStar - 1 && right == 0) {
                    right = des.right;
                }

                canvas.drawBitmap(backBitmap, src, des, paint);
            }
        }

        //画进度
        if (frontBitmap != null) {
            for (int i = 0; i < rating; i++) {
                //画整颗星
                if (i <= rating - 1) {
                    src.left = 0;
                    src.top = 0;
                    src.right = frontBitmap.getWidth();
                    src.bottom = frontBitmap.getHeight();

                    des.left = getPaddingStart() + (desWidth + starSpace) * i;
                    des.top = top;
                    des.right = des.left + desWidth;
                    des.bottom = des.top + desHeight;
                } else {
                    //画最后一个星,可能为半个星等
                    //画整个星的百分比
                    float p = rating - i;
//                   Logger.d(TAG, "onDraw: p="+p);

                    src.left = 0;
                    src.top = 0;
                    src.right = (int) (frontBitmap.getWidth() * p);
                    src.bottom = frontBitmap.getHeight();

                    des.left = getPaddingStart() + (desWidth + starSpace) * i;
                    des.top = top;
                    des.right = (int) ((des.left + desWidth * p));
                    des.bottom = des.top + desHeight;
                }
                canvas.drawBitmap(frontBitmap, src, des, paint);
            }
        }

    }

    /**
     * 设置选中图片
     *
     * @param res
     */
    public void setFrontBitmap(@DrawableRes int res) {
        Drawable drawable = getContext().getResources().getDrawable(res);
        frontBitmap = getBitmap(drawable);
    }

    /**
     * 设置背景图片
     *
     * @param res
     */
    public void setBackBitmap(@DrawableRes int res) {
        Drawable drawable = getContext().getResources().getDrawable(res);
        backBitmap = getBitmap(drawable);
    }


    private Bitmap getBitmap(Drawable drawable) {
        if (drawable == null) return null;
        if (drawable instanceof BitmapDrawable) {
            return ((BitmapDrawable) drawable).getBitmap();
        }
        return null;
    }

    /**
     * 设置星星之间的间隔
     *
     * @param starSpace
     */
    public void setStarSpace(int starSpace) {
        this.starSpace = starSpace;
    }

    /**
     * 设置星星总数目
     *
     * @param maxStar
     */
    public void setMaxStar(int maxStar) {
        this.maxStar = maxStar;
    }

    /**
     * 设置选中的星星数
     *
     * @param rating
     */
    public void setRating(float rating) {
        this.rating = computeRating(rating);
        postInvalidate();
    }

    /**
     * 设置所有星星代表的总进度
     *
     * @param maxProgress
     */
    public void setMaxProgress(int maxProgress) {
        this.maxProgress = maxProgress;
    }

    /**
     * 设置进度,根据maxProgress和maxStar计算出rating
     *
     * @param progress
     */
    public void setProgress(int progress) {
        setRating(rating = progress / (float) maxProgress * maxStar);
    }

    /**
     * 获取进度
     *
     * @return
     */
    public int getProgress() {
        return (int) (maxProgress / maxStar * rating);
    }

    /**
     * 设置星星改变的最小状态 0-1
     *
     * @param stepSize
     */
    public void setStepSize(float stepSize) {
        if (stepSize <= 0 || stepSize > 1) {
            this.stepSize = 1;
        } else {
            this.stepSize = stepSize;
        }
    }

    /**
     * 当前选择的星星数
     *
     * @return
     */
    public float getRating() {
        return rating;
    }

    public int getMaxProgress() {
        return maxProgress;
    }

    public int getMaxStar() {
        return maxStar;
    }

    /**
     * 进度改变监听
     *
     * @param onProgressListener
     */
    public void setOnProgressListener(OnProgressListener onProgressListener) {
        this.mOnProgressListener = onProgressListener;
    }
}
